import math

import Image

import rgbMatrix
reload(rgbMatrix)



class ImageMatcher:
    def __init__(self, images, matrixUnitAsPrecentage, \
                 maximumDifference):

        self.images = images
        self.matrixUnitAsPrecentage = matrixUnitAsPrecentage
        self.maximumDifference = maximumDifference
        self.matrixDimention = self.calculateMatrixDimention()
        
        self.resizedImages = None
        self.rgbMatrixes = None
        
        
    def calculateMatrixDimention(self):
        dimention = 100 / self.matrixUnitAsPrecentage
        dimention = max(1,dimention) #to avoid zero
        return dimention
                
    def findMatch(self, otherImage):
        assert(otherImage != None)
        assert(self.images != None)

        index = self.getMatchIndex(otherImage)               
        return self.resizedImages[index]
        

    def getMatchIndex(self, otherImage):
        if (self.firstCall()):
            self.initWithOtherImage(otherImage)
        grades = []
        otherMatrix = createRgbMatrix(otherImage, self.matrixDimention)
        for matrix in self.rgbMatrixes:
            rgbDifferenceMatrix = matrix.getDifferenceMatrix(otherMatrix)
            scorings = rgbDifferenceMatrix.applyUnaryFunction \
                       (self.compareToMaxDifference)
            scoringsSum = sum(scorings)
            grades.append(scoringsSum)
                
        maxGradeIndex = getIndexOfMax(grades)
        return maxGradeIndex

    def firstCall(self):
        return self.rgbMatrixes == None


    def initWithOtherImage(self,otherImage):
        self.resizedImages = [resizeImage(image, otherImage.size) \
                              for image in self.images]
        self.rgbMatrixes = [createRgbMatrix(image, self.matrixDimention)
                           for image in self.resizedImages]


    def compareToMaxDifference(self,rgb):
        return ((rgb[0] <= self.maximumDifference) and
                (rgb[1] <= self.maximumDifference) and
                (rgb[2] <= self.maximumDifference))
                             
    
def resizeImage(image, size):
    return image.resize(size)

def getIndexOfMax(ls):
    valueIndexPairs = zip(ls,range(len(ls)))
    valueIndexPairs.sort()
    valueIndexPairs.reverse()   
    maxIndex = valueIndexPairs[0][1]
    return maxIndex
    
def createRgbMatrix(image, matrixDimention ):
     pixels = image.getdata()
     totalNumberOfPixels = len(pixels)
     numberOfPixelsPerUnit = totalNumberOfPixels / pow(matrixDimention, 2)
     averages = createUnitsAverages(pixels, numberOfPixelsPerUnit)
     matrix = rgbMatrix.RgbMatrix(matrixDimention, averages)
     return matrix

    
def createUnitsAverages(pixels, numberOfPixelsPerUnit):
    #clear the point - last unit may be smaller than other
    
    unitsStarts = range(0, len(pixels) - numberOfPixelsPerUnit, numberOfPixelsPerUnit)
    unitsLocations = [(start, start + numberOfPixelsPerUnit ) for start in unitsStarts]
    lastUnitLocation = (numberOfPixelsPerUnit * len(unitsLocations) , len(pixels) )
    unitsLocations.append(lastUnitLocation)
    
    unitsAverages = []
    for unitLocation in unitsLocations: 
        unitSum = (0,0,0)   
        for index in range(unitLocation[0],unitLocation[1]):
            unitSum = addRgbs(unitSum, pixels[index])
        unitAverage = divideRgbByNum(unitSum, numberOfPixelsPerUnit)
        unitsAverages.append(unitAverage)

    return unitsAverages

def addRgbs(rgb1, rgb2):
    return (rgb1[0] + rgb2[0], \
            rgb1[1] + rgb2[1], \
            rgb1[2] + rgb2[2])
        
def divideRgbByNum(rgb, num):
    return (rgb[0] / num, rgb[1] / num, rgb[2] / num)
    
    
    